home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume13 / rpc3.9 / part06 < prev    next >
Encoding:
Internet Message Format  |  1988-02-27  |  45.1 KB

  1. Subject:  v13i083:  Sun RPC, release 3.9, Part06/15
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Stephen X. Nahm <sxn@Sun.COM>
  7. Posting-number: Volume 13, Issue 83
  8. Archive-name: rpc3.9/part06
  9.  
  10. #! /bin/sh
  11. # This is a shell archive. To extract, remove the header and type "sh filename"
  12. #
  13. echo x - etc
  14. echo creating directory etc
  15. mkdir etc
  16. cd etc
  17. echo x - Makefile
  18. cat > Makefile <<'Funky_Stuff'
  19. #
  20. # @(#)Makefile    1.5 87/11/20 3.9 RPCSRC
  21. #
  22. #   Files and programs for /etc.  rpclib must have already been installed.
  23. #
  24. DESTDIR=
  25. CFLAGS=    -O
  26. LIB = -lrpclib
  27. LDFLAGS= $(LIB)
  28.  
  29. BIN = portmap rpcinfo
  30. MISC= rpc
  31.  
  32. all:    ${BIN}
  33.  
  34. portmap:
  35.     ${CC} ${CFLAGS} -o $@ $@.c ${LDFLAGS}
  36.  
  37. rpcinfo:    getopt.o
  38.     ${CC} ${CFLAGS} -o $@ $@.c getopt.o ${LDFLAGS}
  39.  
  40. install: ${BIN}
  41.     -mkdir ${DESTDIR}/etc && chown bin ${DESTDIR}/etc && \
  42.         chmod 755 ${DESTDIR}/etc
  43.     @echo "Installing RPC utility files in ${DESTDIR}/etc"
  44.     @set -x;for i in ${BIN}; do \
  45.         (install -s $$i ${DESTDIR}/etc/$$i); done
  46.     @echo "Installing ${DESTDIR}/etc/rpc"
  47.     @set -x;for i in ${MISC}; do \
  48.         (install -c -m 644 $$i ${DESTDIR}/etc/$$i); done
  49.  
  50. clean:
  51.     rm -f core *.o
  52.     rm -f ${BIN}
  53.  
  54. depend: ${BIN}
  55.     rm -f makedep
  56.     for i in ${BIN}; do \
  57.         ${CC} -M ${INCPATH} $$i.c | sed 's/\.o//' | \
  58.         awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
  59.         else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
  60.         else rec = rec " " $$2 } } \
  61.         END { print rec } ' >> makedep; done
  62.     echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
  63.     echo '$$r makedep' >>eddep
  64.     echo 'w' >>eddep
  65.     cp Makefile Makefile.bak
  66.     ed - Makefile < eddep
  67.     rm eddep makedep
  68.     echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
  69.     echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
  70.     echo '# see make depend above' >> Makefile
  71.  
  72.  
  73. depend.42BSD depend.42bsd:
  74.     cp /dev/null x.c
  75.     for i in $(BIN) ; do \
  76.               (/bin/grep '^#[         ]*include' x.c $$i.c | sed \
  77.                       -e 's,<\(.*\)>,"/usr/include/\1",' \
  78.                       -e 's/:[^"]*"\([^"]*\)".*/: \1/' \
  79.                       -e 's/\.c/\.o/' >>makedep); done
  80.     echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
  81.     echo '$$r makedep' >>eddep
  82.     echo 'w' >>eddep
  83.     cp Makefile Makefile.bak
  84.     ed - Makefile < eddep
  85.     rm eddep makedep x.c
  86.     echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
  87.     echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
  88.     echo '# see make depend above' >> Makefile
  89.  
  90. # DO NOT DELETE THIS LINE -- make depend uses it
  91.  
  92.  
  93. Funky_Stuff
  94. len=`wc -c < Makefile`
  95. if [ $len !=     2046 ] ; then
  96.   echo error: Makefile was $len bytes long, should have been     2046
  97. fi
  98. echo x - getopt.c
  99. cat > getopt.c <<'Funky_Stuff'
  100. /* @(#)getopt.c    1.2 87/11/30 3.9 RPCSRC */
  101.  
  102. /* this is a public domain version of getopt */
  103.  
  104. /*LINTLIBRARY*/
  105. #ifndef NULL
  106. #define NULL    0
  107. #endif NULL
  108. #ifndef EOF
  109. #define EOF    (-1)
  110. #endif EOF
  111.  
  112. #define ERR(s, c)    if(opterr){\
  113.     extern int strlen(), write();\
  114.     char errbuf[2];\
  115.     errbuf[0] = c; errbuf[1] = '\n';\
  116.     (void) write(2, argv[0], strlen(argv[0]));\
  117.     (void) write(2, s, strlen(s));\
  118.     (void) write(2, errbuf, 2);}
  119.  
  120. #define strchr index
  121.  
  122. extern int strcmp();
  123. extern char *strchr();
  124.  
  125. int    opterr = 1;
  126. int    optind = 1;
  127. int    optopt;
  128. char    *optarg;
  129.  
  130. int
  131. getopt(argc, argv, opts)
  132. int    argc;
  133. char    **argv, *opts;
  134. {
  135.     static int sp = 1;
  136.     register int c;
  137.     register char *cp;
  138.  
  139.     if(sp == 1)
  140.         if(optind >= argc ||
  141.            argv[optind][0] != '-' || argv[optind][1] == '\0')
  142.             return(EOF);
  143.         else if(strcmp(argv[optind], "--") == NULL) {
  144.             optind++;
  145.             return(EOF);
  146.         }
  147.     optopt = c = argv[optind][sp];
  148.     if(c == ':' || (cp=strchr(opts, c)) == NULL) {
  149.         ERR(": unknown option, -", c);
  150.         if(argv[optind][++sp] == '\0') {
  151.             optind++;
  152.             sp = 1;
  153.         }
  154.         return('?');
  155.     }
  156.     if(*++cp == ':') {
  157.         if(argv[optind][sp+1] != '\0')
  158.             optarg = &argv[optind++][sp+1];
  159.         else if(++optind >= argc) {
  160.             ERR(": argument missing for -", c);
  161.             sp = 1;
  162.             return('?');
  163.         } else
  164.             optarg = argv[optind++];
  165.         sp = 1;
  166.     } else {
  167.         if(argv[optind][++sp] == '\0') {
  168.             sp = 1;
  169.             optind++;
  170.         }
  171.         optarg = NULL;
  172.     }
  173.     return(c);
  174. }
  175. Funky_Stuff
  176. len=`wc -c < getopt.c`
  177. if [ $len !=     1381 ] ; then
  178.   echo error: getopt.c was $len bytes long, should have been     1381
  179. fi
  180. echo x - portmap.c
  181. cat > portmap.c <<'Funky_Stuff'
  182. /* @(#)portmap.c    1.1 87/11/04 3.9 RPCSRC */
  183. #ifndef lint
  184. static    char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
  185. #endif
  186.  
  187. /*
  188.  * Copyright (c) 1984 by Sun Microsystems, Inc.
  189.  */
  190.  
  191. /*
  192.  * portmap.c, Implements the program,version to port number mapping for
  193.  * rpc.
  194.  */
  195.  
  196. /*
  197.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  198.  * unrestricted use provided that this legend is included on all tape
  199.  * media and as a part of the software program in whole or part.  Users
  200.  * may copy or modify Sun RPC without charge, but are not authorized
  201.  * to license or distribute it to anyone else except as part of a product or
  202.  * program developed by the user.
  203.  * 
  204.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  205.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  206.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  207.  * 
  208.  * Sun RPC is provided with no support and without any obligation on the
  209.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  210.  * modification or enhancement.
  211.  * 
  212.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  213.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  214.  * OR ANY PART THEREOF.
  215.  * 
  216.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  217.  * or profits or other special, indirect and consequential damages, even if
  218.  * Sun has been advised of the possibility of such damages.
  219.  * 
  220.  * Sun Microsystems, Inc.
  221.  * 2550 Garcia Avenue
  222.  * Mountain View, California  94043
  223.  */
  224.  
  225. #include <rpc/rpc.h>
  226. #include <rpc/pmap_prot.h>
  227. #include <stdio.h>
  228. #include <netdb.h>
  229. #include <sys/socket.h>
  230. #include <sys/time.h>
  231. #include <sys/ioctl.h>
  232. #include <sys/wait.h>
  233.  
  234. char *malloc();
  235. int reg_service();
  236. struct pmaplist *pmaplist;
  237. static int debugging = 0;
  238.  
  239. main()
  240. {
  241.     SVCXPRT *xprt;
  242.     int sock, pid, t;
  243.     struct sockaddr_in addr;
  244.     int len = sizeof(struct sockaddr_in);
  245.     register struct pmaplist *pml;
  246.  
  247. #ifndef DEBUG
  248.     pid = fork();
  249.     if (pid < 0) {
  250.         perror("portmap: fork");
  251.         exit(1);
  252.     }
  253.     if (pid != 0)
  254.         exit(0);
  255.     for (t = 0; t < 20; t++)
  256.         close(t);
  257.      open("/", 0);
  258.      dup2(0, 1);
  259.      dup2(0, 2);
  260.      t = open("/dev/tty", 2);
  261.      if (t >= 0) {
  262.          ioctl(t, TIOCNOTTY, (char *)0);
  263.          close(t);
  264.      }
  265. #endif
  266.     if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
  267.         perror("portmap cannot create socket");
  268.         exit(1);
  269.     }
  270.  
  271.     addr.sin_addr.s_addr = 0;
  272.     addr.sin_family = AF_INET;
  273.     addr.sin_port = htons(PMAPPORT);
  274.     if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
  275.         perror("portmap cannot bind");
  276.         exit(1);
  277.     }
  278.  
  279.     if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
  280.         fprintf(stderr, "couldn't do udp_create\n");
  281.         exit(1);
  282.     }
  283.     /* make an entry for ourself */
  284.     pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
  285.     pml->pml_next = 0;
  286.     pml->pml_map.pm_prog = PMAPPROG;
  287.     pml->pml_map.pm_vers = PMAPVERS;
  288.     pml->pml_map.pm_prot = IPPROTO_UDP;
  289.     pml->pml_map.pm_port = PMAPPORT;
  290.     pmaplist = pml;
  291.  
  292.     if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  293.         perror("portmap cannot create socket");
  294.         exit(1);
  295.     }
  296.     if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
  297.         perror("portmap cannot bind");
  298.         exit(1);
  299.     }
  300.     if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
  301.         == (SVCXPRT *)NULL) {
  302.         fprintf(stderr, "couldn't do tcp_create\n");
  303.         exit(1);
  304.     }
  305.     /* make an entry for ourself */
  306.     pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
  307.     pml->pml_map.pm_prog = PMAPPROG;
  308.     pml->pml_map.pm_vers = PMAPVERS;
  309.     pml->pml_map.pm_prot = IPPROTO_TCP;
  310.     pml->pml_map.pm_port = PMAPPORT;
  311.     pml->pml_next = pmaplist;
  312.     pmaplist = pml;
  313.  
  314.     (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
  315.     svc_run();
  316.     fprintf(stderr, "run_svc returned unexpectedly\n");
  317.     abort();
  318. }
  319.  
  320. static struct pmaplist *
  321. find_service(prog, vers, prot)
  322.     u_long prog;
  323.     u_long vers;
  324. {
  325.     register struct pmaplist *hit = NULL;
  326.     register struct pmaplist *pml;
  327.  
  328.     for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
  329.         if ((pml->pml_map.pm_prog != prog) ||
  330.             (pml->pml_map.pm_prot != prot))
  331.             continue;
  332.         hit = pml;
  333.         if (pml->pml_map.pm_vers == vers)
  334.             break;
  335.     }
  336.     return (hit);
  337. }
  338.  
  339. /* 
  340.  * 1 OK, 0 not
  341.  */
  342. reg_service(rqstp, xprt)
  343.     struct svc_req *rqstp;
  344.     SVCXPRT *xprt;
  345. {
  346.     struct pmap reg;
  347.     struct pmaplist *pml, *prevpml, *fnd;
  348.     int ans, port;
  349.     caddr_t t;
  350.     
  351. #ifdef DEBUG
  352.     fprintf(stderr, "server: about do a switch\n");
  353. #endif
  354.     switch (rqstp->rq_proc) {
  355.  
  356.     case PMAPPROC_NULL:
  357.         /*
  358.          * Null proc call
  359.          */
  360.         if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) {
  361.             abort();
  362.         }
  363.         break;
  364.  
  365.     case PMAPPROC_SET:
  366.         /*
  367.          * Set a program,version to port mapping
  368.          */
  369.         if (!svc_getargs(xprt, xdr_pmap, ®))
  370.             svcerr_decode(xprt);
  371.         else {
  372.             /*
  373.              * check to see if already used
  374.              * find_service returns a hit even if
  375.              * the versions don't match, so check for it
  376.              */
  377.             fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
  378.             if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
  379.                 if (fnd->pml_map.pm_port == reg.pm_port) {
  380.                     ans = 1;
  381.                     goto done;
  382.                 }
  383.                 else {
  384.                     ans = 0;
  385.                     goto done;
  386.                 }
  387.             } else {
  388.                 /* 
  389.                  * add to END of list
  390.                  */
  391.                 pml = (struct pmaplist *)
  392.                     malloc((u_int)sizeof(struct pmaplist));
  393.                 pml->pml_map = reg;
  394.                 pml->pml_next = 0;
  395.                 if (pmaplist == 0) {
  396.                     pmaplist = pml;
  397.                 } else {
  398.                     for (fnd= pmaplist; fnd->pml_next != 0;
  399.                         fnd = fnd->pml_next);
  400.                     fnd->pml_next = pml;
  401.                 }
  402.                 ans = 1;
  403.             }
  404.         done:
  405.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
  406.                 debugging) {
  407.                 fprintf(stderr, "svc_sendreply\n");
  408.                 abort();
  409.             }
  410.         }
  411.         break;
  412.  
  413.     case PMAPPROC_UNSET:
  414.         /*
  415.          * Remove a program,version to port mapping.
  416.          */
  417.         if (!svc_getargs(xprt, xdr_pmap, ®))
  418.             svcerr_decode(xprt);
  419.         else {
  420.             ans = 0;
  421.             for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
  422.                 if ((pml->pml_map.pm_prog != reg.pm_prog) ||
  423.                     (pml->pml_map.pm_vers != reg.pm_vers)) {
  424.                     /* both pml & prevpml move forwards */
  425.                     prevpml = pml;
  426.                     pml = pml->pml_next;
  427.                     continue;
  428.                 }
  429.                 /* found it; pml moves forward, prevpml stays */
  430.                 ans = 1;
  431.                 t = (caddr_t)pml;
  432.                 pml = pml->pml_next;
  433.                 if (prevpml == NULL)
  434.                     pmaplist = pml;
  435.                 else
  436.                     prevpml->pml_next = pml;
  437.                 free(t);
  438.             }
  439.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
  440.                 debugging) {
  441.                 fprintf(stderr, "svc_sendreply\n");
  442.                 abort();
  443.             }
  444.         }
  445.         break;
  446.  
  447.     case PMAPPROC_GETPORT:
  448.         /*
  449.          * Lookup the mapping for a program,version and return its port
  450.          */
  451.         if (!svc_getargs(xprt, xdr_pmap, ®))
  452.             svcerr_decode(xprt);
  453.         else {
  454.             fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
  455.             if (fnd)
  456.                 port = fnd->pml_map.pm_port;
  457.             else
  458.                 port = 0;
  459.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
  460.                 debugging) {
  461.                 fprintf(stderr, "svc_sendreply\n");
  462.                 abort();
  463.             }
  464.         }
  465.         break;
  466.  
  467.     case PMAPPROC_DUMP:
  468.         /*
  469.          * Return the current set of mapped program,version
  470.          */
  471.         if (!svc_getargs(xprt, xdr_void, NULL))
  472.             svcerr_decode(xprt);
  473.         else {
  474.             if ((!svc_sendreply(xprt, xdr_pmaplist,
  475.                 (caddr_t)&pmaplist)) && debugging) {
  476.                 fprintf(stderr, "svc_sendreply\n");
  477.                 abort();
  478.             }
  479.         }
  480.         break;
  481.  
  482.     case PMAPPROC_CALLIT:
  483.         /*
  484.          * Calls a procedure on the local machine.  If the requested
  485.          * procedure is not registered this procedure does not return
  486.          * error information!!
  487.          * This procedure is only supported on rpc/udp and calls via 
  488.          * rpc/udp.  It passes null authentication parameters.
  489.          */
  490.         callit(rqstp, xprt);
  491.         break;
  492.  
  493.     default:
  494.         svcerr_noproc(xprt);
  495.         break;
  496.     }
  497. }
  498.  
  499.  
  500. /*
  501.  * Stuff for the rmtcall service
  502.  */
  503. #define ARGSIZE 9000
  504.  
  505. typedef struct encap_parms {
  506.     u_long arglen;
  507.     char *args;
  508. };
  509.  
  510. static bool_t
  511. xdr_encap_parms(xdrs, epp)
  512.     XDR *xdrs;
  513.     struct encap_parms *epp;
  514. {
  515.  
  516.     return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
  517. }
  518.  
  519. typedef struct rmtcallargs {
  520.     u_long    rmt_prog;
  521.     u_long    rmt_vers;
  522.     u_long    rmt_port;
  523.     u_long    rmt_proc;
  524.     struct encap_parms rmt_args;
  525. };
  526.  
  527. static bool_t
  528. xdr_rmtcall_args(xdrs, cap)
  529.     register XDR *xdrs;
  530.     register struct rmtcallargs *cap;
  531. {
  532.  
  533.     /* does not get a port number */
  534.     if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
  535.         xdr_u_long(xdrs, &(cap->rmt_vers)) &&
  536.         xdr_u_long(xdrs, &(cap->rmt_proc))) {
  537.         return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
  538.     }
  539.     return (FALSE);
  540. }
  541.  
  542. static bool_t
  543. xdr_rmtcall_result(xdrs, cap)
  544.     register XDR *xdrs;
  545.     register struct rmtcallargs *cap;
  546. {
  547.     if (xdr_u_long(xdrs, &(cap->rmt_port)))
  548.         return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
  549.     return (FALSE);
  550. }
  551.  
  552. /*
  553.  * only worries about the struct encap_parms part of struct rmtcallargs.
  554.  * The arglen must already be set!!
  555.  */
  556. static bool_t
  557. xdr_opaque_parms(xdrs, cap)
  558.     XDR *xdrs;
  559.     struct rmtcallargs *cap;
  560. {
  561.  
  562.     return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
  563. }
  564.  
  565. /*
  566.  * This routine finds and sets the length of incoming opaque paraters
  567.  * and then calls xdr_opaque_parms.
  568.  */
  569. static bool_t
  570. xdr_len_opaque_parms(xdrs, cap)
  571.     register XDR *xdrs;
  572.     struct rmtcallargs *cap;
  573. {
  574.     register u_int beginpos, lowpos, highpos, currpos, pos;
  575.  
  576.     beginpos = lowpos = pos = xdr_getpos(xdrs);
  577.     highpos = lowpos + ARGSIZE;
  578.     while ((int)(highpos - lowpos) >= 0) {
  579.         currpos = (lowpos + highpos) / 2;
  580.         if (xdr_setpos(xdrs, currpos)) {
  581.             pos = currpos;
  582.             lowpos = currpos + 1;
  583.         } else {
  584.             highpos = currpos - 1;
  585.         }
  586.     }
  587.     xdr_setpos(xdrs, beginpos);
  588.     cap->rmt_args.arglen = pos - beginpos;
  589.     return (xdr_opaque_parms(xdrs, cap));
  590. }
  591.  
  592. /*
  593.  * Call a remote procedure service
  594.  * This procedure is very quiet when things go wrong.
  595.  * The proc is written to support broadcast rpc.  In the broadcast case,
  596.  * a machine should shut-up instead of complain, less the requestor be
  597.  * overrun with complaints at the expense of not hearing a valid reply ...
  598.  *
  599.  * This now forks so that the program & process that it calls can call 
  600.  * back to the portmapper.
  601.  */
  602. static
  603. callit(rqstp, xprt)
  604.     struct svc_req *rqstp;
  605.     SVCXPRT *xprt;
  606. {
  607.     struct rmtcallargs a;
  608.     struct pmaplist *pml;
  609.     u_short port;
  610.     struct sockaddr_in me;
  611.     int pid, socket = -1;
  612.     CLIENT *client;
  613.     struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
  614.     struct timeval timeout;
  615.     union wait pinfo;
  616.     char buf[ARGSIZE];
  617.  
  618.     timeout.tv_sec = 5;
  619.     timeout.tv_usec = 0;
  620.     a.rmt_args.args = buf;
  621.     if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
  622.         return;
  623.     if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
  624.         return;
  625.     /*
  626.      * fork a child to do the work.  Parent immediately returns.
  627.      * Child exits upon completion.
  628.      */
  629.     if ((pid = fork()) != 0) {
  630.         if (debugging && (pid < 0)) {
  631.             fprintf(stderr, "portmap CALLIT: cannot fork.\n");
  632.         }
  633.         /* reap previous forks. */
  634.         for (; pid>0; pid = wait3(&pinfo, WNOHANG, (struct rusage *)0));
  635.         return;
  636.     }
  637.     port = pml->pml_map.pm_port;
  638.     get_myaddress(&me);
  639.     me.sin_port = htons(port);
  640.     client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket);
  641.     if (client != (CLIENT *)NULL) {
  642.         if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
  643.             client->cl_auth = authunix_create(au->aup_machname,
  644.                au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
  645.         }
  646.         a.rmt_port = (u_long)port;
  647.         if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
  648.             xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
  649.             svc_sendreply(xprt, xdr_rmtcall_result, &a);
  650.         }
  651.         AUTH_DESTROY(client->cl_auth);
  652.         clnt_destroy(client);
  653.     }
  654.     (void)close(socket);
  655.     exit(0);
  656. }
  657. Funky_Stuff
  658. len=`wc -c < portmap.c`
  659. if [ $len !=    11403 ] ; then
  660.   echo error: portmap.c was $len bytes long, should have been    11403
  661. fi
  662. echo x - rpc
  663. cat > rpc <<'Funky_Stuff'
  664. #
  665. # rpc 87/12/02 3.9 RPCSRC
  666. #
  667. portmapper    100000  portmap sunrpc
  668. rstat_svc     100001  rstatd rstat rup perfmeter
  669. rusersd       100002  rusers
  670. nfs           100003  nfsprog
  671. ypserv        100004  ypprog
  672. mountd        100005  mount showmount
  673. ypbind        100007
  674. walld         100008  rwall shutdown
  675. yppasswdd     100009  yppasswd
  676. etherstatd    100010  etherstat
  677. rquotad       100011  rquotaprog quota rquota
  678. sprayd        100012  spray
  679. 3270_mapper   100013
  680. rje_mapper    100014
  681. selection_svc 100015  selnsvc
  682. database_svc  100016
  683. rexd          100017  rex
  684. alis          100018
  685. sched         100019
  686. llockmgr      100020
  687. nlockmgr      100021
  688. x25.inr       100022
  689. statmon       100023
  690. status        100024
  691. bootparam     100026
  692. ypupdated     100028  ypupdate
  693. keyserv       100029  keyserver
  694. Funky_Stuff
  695. len=`wc -c < rpc`
  696. if [ $len !=      787 ] ; then
  697.   echo error: rpc was $len bytes long, should have been      787
  698. fi
  699. echo x - rpcinfo.c
  700. cat > rpcinfo.c <<'Funky_Stuff'
  701. /* @(#)rpcinfo.c    1.5 87/11/20 3.9 RPCSRC */
  702. #ifndef lint
  703. static    char sccsid[] = "@(#)rpcinfo.c 1.22 87/08/12 SMI";
  704. #endif
  705.  
  706. /*
  707.  * Copyright (C) 1986, Sun Microsystems, Inc.
  708.  */
  709.  
  710. /*
  711.  * rpcinfo: ping a particular rpc program
  712.  *     or dump the portmapper
  713.  */
  714.  
  715. /*
  716.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  717.  * unrestricted use provided that this legend is included on all tape
  718.  * media and as a part of the software program in whole or part.  Users
  719.  * may copy or modify Sun RPC without charge, but are not authorized
  720.  * to license or distribute it to anyone else except as part of a product or
  721.  * program developed by the user.
  722.  * 
  723.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  724.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  725.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  726.  * 
  727.  * Sun RPC is provided with no support and without any obligation on the
  728.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  729.  * modification or enhancement.
  730.  * 
  731.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  732.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  733.  * OR ANY PART THEREOF.
  734.  * 
  735.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  736.  * or profits or other special, indirect and consequential damages, even if
  737.  * Sun has been advised of the possibility of such damages.
  738.  * 
  739.  * Sun Microsystems, Inc.
  740.  * 2550 Garcia Avenue
  741.  * Mountain View, California  94043
  742.  */
  743.  
  744. #include <rpc/rpc.h>
  745. #include <stdio.h>
  746. #include <sys/socket.h>
  747. #include <sys/time.h>
  748. #include <netdb.h>
  749. #include <rpc/pmap_prot.h>
  750. #include <rpc/pmap_clnt.h>
  751. #include <signal.h>
  752. #include <ctype.h>
  753.  
  754. #define MAXHOSTLEN 256
  755.  
  756. #define    MIN_VERS    ((u_long) 0)
  757. #define    MAX_VERS    ((u_long) 4294967295L)
  758.  
  759. static void    udpping(/*u_short portflag, int argc, char **argv*/);
  760. static void    tcpping(/*u_short portflag, int argc, char **argv*/);
  761. static int    pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
  762. static void    pmapdump(/*int argc, char **argv*/);
  763. static bool_t    reply_proc(/*void *res, struct sockaddr_in *who*/);
  764. static void    brdcst(/*int argc, char **argv*/);
  765. static void    usage(/*void*/);
  766. static u_long    getprognum(/*char *arg*/);
  767. static u_long    getvers(/*char *arg*/);
  768. static void    get_inet_address(/*struct sockaddr_in *addr, char *host*/);
  769. extern u_long inet_addr();  /* in 4.2BSD, arpa/inet.h called that a in_addr */
  770. extern char *inet_ntoa();
  771.  
  772. /*
  773.  * Functions to be performed.
  774.  */
  775. #define    NONE        0    /* no function */
  776. #define    PMAPDUMP    1    /* dump portmapper registrations */
  777. #define    TCPPING        2    /* ping TCP service */
  778. #define    UDPPING        3    /* ping UDP service */
  779. #define    BRDCST        4    /* ping broadcast UDP service */
  780.  
  781. int
  782. main(argc, argv)
  783.     int argc;
  784.     char **argv;
  785. {
  786.     register int c;
  787.     extern char *optarg;
  788.     extern int optind;
  789.     int errflg;
  790.     int function;
  791.     u_short portnum;
  792.  
  793.     function = NONE;
  794.     portnum = 0;
  795.     errflg = 0;
  796.     while ((c = getopt(argc, argv, "ptubn:")) != EOF) {
  797.         switch (c) {
  798.  
  799.         case 'p':
  800.             if (function != NONE)
  801.                 errflg = 1;
  802.             else
  803.                 function = PMAPDUMP;
  804.             break;
  805.  
  806.         case 't':
  807.             if (function != NONE)
  808.                 errflg = 1;
  809.             else
  810.                 function = TCPPING;
  811.             break;
  812.  
  813.         case 'u':
  814.             if (function != NONE)
  815.                 errflg = 1;
  816.             else
  817.                 function = UDPPING;
  818.             break;
  819.  
  820.         case 'b':
  821.             if (function != NONE)
  822.                 errflg = 1;
  823.             else
  824.                 function = BRDCST;
  825.             break;
  826.  
  827.         case 'n':
  828.             portnum = (u_short) atoi(optarg);   /* hope we don't get bogus # */
  829.             break;
  830.  
  831.         case '?':
  832.             errflg = 1;
  833.         }
  834.     }
  835.  
  836.     if (errflg || function == NONE) {
  837.         usage();
  838.         return (1);
  839.     }
  840.  
  841.     switch (function) {
  842.  
  843.     case PMAPDUMP:
  844.         if (portnum != 0) {
  845.             usage();
  846.             return (1);
  847.         }
  848.         pmapdump(argc - optind, argv + optind);
  849.         break;
  850.  
  851.     case UDPPING:
  852.         udpping(portnum, argc - optind, argv + optind);
  853.         break;
  854.  
  855.     case TCPPING:
  856.         tcpping(portnum, argc - optind, argv + optind);
  857.         break;
  858.  
  859.     case BRDCST:
  860.         if (portnum != 0) {
  861.             usage();
  862.             return (1);
  863.         }
  864.         brdcst(argc - optind, argv + optind);
  865.         break;
  866.     }
  867.  
  868.     return (0);
  869. }
  870.         
  871. static void
  872. udpping(portnum, argc, argv)
  873.     u_short portnum;
  874.     int argc;
  875.     char **argv;
  876. {
  877.     struct timeval to;
  878.     struct sockaddr_in addr;
  879.     enum clnt_stat rpc_stat;
  880.     CLIENT *client;
  881.     u_long prognum, vers, minvers, maxvers;
  882.     int sock = RPC_ANYSOCK;
  883.     struct rpc_err rpcerr;
  884.     int failure;
  885.     
  886.     if (argc < 2 || argc > 3) {
  887.         usage();
  888.         exit(1);
  889.     }
  890.     prognum = getprognum(argv[1]);
  891.     get_inet_address(&addr, argv[0]);
  892.     /* Open the socket here so it will survive calls to clnt_destroy */
  893.     sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  894.     if (sock < 0) {
  895.         perror("rpcinfo: socket");
  896.         exit(1);
  897.     }
  898.     failure = 0;
  899.     if (argc == 2) {
  900.         /*
  901.          * A call to version 0 should fail with a program/version
  902.          * mismatch, and give us the range of versions supported.
  903.          */
  904.         addr.sin_port = htons(portnum);
  905.         to.tv_sec = 5;
  906.         to.tv_usec = 0;
  907.         if ((client = clntudp_create(&addr, prognum, (u_long)0,
  908.             to, &sock)) == NULL) {
  909.             clnt_pcreateerror("rpcinfo");
  910.             printf("program %lu is not available\n",
  911.                 prognum);
  912.             exit(1);
  913.         }
  914.         to.tv_sec = 10;
  915.         to.tv_usec = 0;
  916.         rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
  917.             xdr_void, (char *)NULL, to);
  918.         if (rpc_stat == RPC_PROGVERSMISMATCH) {
  919.             clnt_geterr(client, &rpcerr);
  920.             minvers = rpcerr.re_vers.low;
  921.             maxvers = rpcerr.re_vers.high;
  922.         } else if (rpc_stat == RPC_SUCCESS) {
  923.             /*
  924.              * Oh dear, it DOES support version 0.
  925.              * Let's try version MAX_VERS.
  926.              */
  927.             addr.sin_port = htons(portnum);
  928.             to.tv_sec = 5;
  929.             to.tv_usec = 0;
  930.             if ((client = clntudp_create(&addr, prognum, MAX_VERS,
  931.                 to, &sock)) == NULL) {
  932.                 clnt_pcreateerror("rpcinfo");
  933.                 printf("program %lu version %lu is not available\n",
  934.                     prognum, MAX_VERS);
  935.                 exit(1);
  936.             }
  937.             to.tv_sec = 10;
  938.             to.tv_usec = 0;
  939.             rpc_stat = clnt_call(client, NULLPROC, xdr_void,
  940.                 (char *)NULL, xdr_void, (char *)NULL, to);
  941.             if (rpc_stat == RPC_PROGVERSMISMATCH) {
  942.                 clnt_geterr(client, &rpcerr);
  943.                 minvers = rpcerr.re_vers.low;
  944.                 maxvers = rpcerr.re_vers.high;
  945.             } else if (rpc_stat == RPC_SUCCESS) {
  946.                 /*
  947.                  * It also supports version MAX_VERS.
  948.                  * Looks like we have a wise guy.
  949.                  * OK, we give them information on all
  950.                  * 4 billion versions they support...
  951.                  */
  952.                 minvers = 0;
  953.                 maxvers = MAX_VERS;
  954.             } else {
  955.                 (void) pstatus(client, prognum, MAX_VERS);
  956.                 exit(1);
  957.             }
  958.         } else {
  959.             (void) pstatus(client, prognum, (u_long)0);
  960.             exit(1);
  961.         }
  962.         clnt_destroy(client);
  963.         for (vers = minvers; vers <= maxvers; vers++) {
  964.             addr.sin_port = htons(portnum);
  965.             to.tv_sec = 5;
  966.             to.tv_usec = 0;
  967.             if ((client = clntudp_create(&addr, prognum, vers,
  968.                 to, &sock)) == NULL) {
  969.                 clnt_pcreateerror("rpcinfo");
  970.                 printf("program %lu version %lu is not available\n",
  971.                     prognum, vers);
  972.                 exit(1);
  973.             }
  974.             to.tv_sec = 10;
  975.             to.tv_usec = 0;
  976.             rpc_stat = clnt_call(client, NULLPROC, xdr_void,
  977.                 (char *)NULL, xdr_void, (char *)NULL, to);
  978.             if (pstatus(client, prognum, vers) < 0)
  979.                 failure = 1;
  980.             clnt_destroy(client);
  981.         }
  982.     }
  983.     else {
  984.         vers = getvers(argv[2]);
  985.         addr.sin_port = htons(portnum);
  986.         to.tv_sec = 5;
  987.         to.tv_usec = 0;
  988.         if ((client = clntudp_create(&addr, prognum, vers,
  989.             to, &sock)) == NULL) {
  990.             clnt_pcreateerror("rpcinfo");
  991.             printf("program %lu version %lu is not available\n",
  992.                 prognum, vers);
  993.             exit(1);
  994.         }
  995.         to.tv_sec = 10;
  996.         to.tv_usec = 0;
  997.         rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
  998.             xdr_void, (char *)NULL, to);
  999.         if (pstatus(client, prognum, vers) < 0)
  1000.             failure = 1;
  1001.     }
  1002.     (void) close(sock); /* Close it up again */
  1003.     if (failure)
  1004.         exit(1);
  1005. }
  1006.  
  1007. static void
  1008. tcpping(portnum, argc, argv)
  1009.     u_short portnum;
  1010.     int argc;
  1011.     char **argv;
  1012. {
  1013.     struct timeval to;
  1014.     struct sockaddr_in addr;
  1015.     enum clnt_stat rpc_stat;
  1016.     CLIENT *client;
  1017.     u_long prognum, vers, minvers, maxvers;
  1018.     int sock = RPC_ANYSOCK;
  1019.     struct rpc_err rpcerr;
  1020.     int failure;
  1021.  
  1022.     if (argc < 2 || argc > 3) {
  1023.         usage();
  1024.         exit(1);
  1025.     }
  1026.     prognum = getprognum(argv[1]);
  1027.     get_inet_address(&addr, argv[0]);
  1028.     failure = 0;
  1029.     if (argc == 2) {
  1030.         /*
  1031.          * A call to version 0 should fail with a program/version
  1032.          * mismatch, and give us the range of versions supported.
  1033.          */
  1034.         addr.sin_port = htons(portnum);
  1035.         if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
  1036.             &sock, 0, 0)) == NULL) {
  1037.             clnt_pcreateerror("rpcinfo");
  1038.             printf("program %lu is not available\n",
  1039.                 prognum);
  1040.             exit(1);
  1041.         }
  1042.         to.tv_sec = 10;
  1043.         to.tv_usec = 0;
  1044.         rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
  1045.             xdr_void, (char *)NULL, to);
  1046.         if (rpc_stat == RPC_PROGVERSMISMATCH) {
  1047.             clnt_geterr(client, &rpcerr);
  1048.             minvers = rpcerr.re_vers.low;
  1049.             maxvers = rpcerr.re_vers.high;
  1050.         } else if (rpc_stat == RPC_SUCCESS) {
  1051.             /*
  1052.              * Oh dear, it DOES support version 0.
  1053.              * Let's try version MAX_VERS.
  1054.              */
  1055.             addr.sin_port = htons(portnum);
  1056.             if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
  1057.                 &sock, 0, 0)) == NULL) {
  1058.                 clnt_pcreateerror("rpcinfo");
  1059.                 printf("program %lu version %lu is not available\n",
  1060.                     prognum, MAX_VERS);
  1061.                 exit(1);
  1062.             }
  1063.             to.tv_sec = 10;
  1064.             to.tv_usec = 0;
  1065.             rpc_stat = clnt_call(client, NULLPROC, xdr_void,
  1066.                 (char *)NULL, xdr_void, (char *)NULL, to);
  1067.             if (rpc_stat == RPC_PROGVERSMISMATCH) {
  1068.                 clnt_geterr(client, &rpcerr);
  1069.                 minvers = rpcerr.re_vers.low;
  1070.                 maxvers = rpcerr.re_vers.high;
  1071.             } else if (rpc_stat == RPC_SUCCESS) {
  1072.                 /*
  1073.                  * It also supports version MAX_VERS.
  1074.                  * Looks like we have a wise guy.
  1075.                  * OK, we give them information on all
  1076.                  * 4 billion versions they support...
  1077.                  */
  1078.                 minvers = 0;
  1079.                 maxvers = MAX_VERS;
  1080.             } else {
  1081.                 (void) pstatus(client, prognum, MAX_VERS);
  1082.                 exit(1);
  1083.             }
  1084.         } else {
  1085.             (void) pstatus(client, prognum, MIN_VERS);
  1086.             exit(1);
  1087.         }
  1088.         clnt_destroy(client);
  1089.         (void) close(sock);
  1090.         sock = RPC_ANYSOCK; /* Re-initialize it for later */
  1091.         for (vers = minvers; vers <= maxvers; vers++) {
  1092.             addr.sin_port = htons(portnum);
  1093.             if ((client = clnttcp_create(&addr, prognum, vers,
  1094.                 &sock, 0, 0)) == NULL) {
  1095.                 clnt_pcreateerror("rpcinfo");
  1096.                 printf("program %lu version %lu is not available\n",
  1097.                     prognum, vers);
  1098.                 exit(1);
  1099.             }
  1100.             to.tv_usec = 0;
  1101.             to.tv_sec = 10;
  1102.             rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
  1103.                 xdr_void, (char *)NULL, to);
  1104.             if (pstatus(client, prognum, vers) < 0)
  1105.                 failure = 1;
  1106.             clnt_destroy(client);
  1107.             (void) close(sock);
  1108.             sock = RPC_ANYSOCK;
  1109.         }
  1110.     }
  1111.     else {
  1112.         vers = getvers(argv[2]);
  1113.         addr.sin_port = htons(portnum);
  1114.         if ((client = clnttcp_create(&addr, prognum, vers, &sock,
  1115.             0, 0)) == NULL) {
  1116.             clnt_pcreateerror("rpcinfo");
  1117.             printf("program %lu version %lu is not available\n",
  1118.                 prognum, vers);
  1119.             exit(1);
  1120.         }
  1121.         to.tv_usec = 0;
  1122.         to.tv_sec = 10;
  1123.         rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
  1124.             xdr_void, (char *)NULL, to);
  1125.         if (pstatus(client, prognum, vers) < 0)
  1126.             failure = 1;
  1127.     }
  1128.     if (failure)
  1129.         exit(1);
  1130. }
  1131.  
  1132. /*
  1133.  * This routine should take a pointer to an "rpc_err" structure, rather than
  1134.  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
  1135.  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
  1136.  * As such, we have to keep the CLIENT structure around in order to print
  1137.  * a good error message.
  1138.  */
  1139. static int
  1140. pstatus(client, prognum, vers)
  1141.     register CLIENT *client;
  1142.     u_long prognum;
  1143.     u_long vers;
  1144. {
  1145.     struct rpc_err rpcerr;
  1146.  
  1147.     clnt_geterr(client, &rpcerr);
  1148.     if (rpcerr.re_status != RPC_SUCCESS) {
  1149.         clnt_perror(client, "rpcinfo");
  1150.         printf("program %lu version %lu is not available\n",
  1151.             prognum, vers);
  1152.         return (-1);
  1153.     } else {
  1154.         printf("program %lu version %lu ready and waiting\n",
  1155.             prognum, vers);
  1156.         return (0);
  1157.     }
  1158. }
  1159.  
  1160. static void
  1161. pmapdump(argc, argv)
  1162.     int argc;
  1163.     char **argv;
  1164. {
  1165.     struct sockaddr_in server_addr;
  1166.     register struct hostent *hp;
  1167.     struct pmaplist *head = NULL;
  1168.     int socket = RPC_ANYSOCK;
  1169.     struct timeval minutetimeout;
  1170.     register CLIENT *client;
  1171.     struct rpcent *rpc;
  1172.     
  1173.     if (argc > 1) {
  1174.         usage();
  1175.         exit(1);
  1176.     }
  1177.     if (argc == 1)
  1178.         get_inet_address(&server_addr, argv[0]);
  1179.     else {
  1180.         bzero((char *)&server_addr, sizeof server_addr);
  1181.         server_addr.sin_family = AF_INET;
  1182.         if ((hp = gethostbyname("localhost")) != NULL)
  1183.             bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
  1184.                 hp->h_length);
  1185.         else
  1186.             server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
  1187.     }
  1188.     minutetimeout.tv_sec = 60;
  1189.     minutetimeout.tv_usec = 0;
  1190.     server_addr.sin_port = htons(PMAPPORT);
  1191.     if ((client = clnttcp_create(&server_addr, PMAPPROG,
  1192.         PMAPVERS, &socket, 50, 500)) == NULL) {
  1193.         clnt_pcreateerror("rpcinfo: can't contact portmapper");
  1194.         exit(1);
  1195.     }
  1196.     if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
  1197.         xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
  1198.         fprintf(stderr, "rpcinfo: can't contact portmapper: ");
  1199.         clnt_perror(client, "rpcinfo");
  1200.         exit(1);
  1201.     }
  1202.     if (head == NULL) {
  1203.         printf("No remote programs registered.\n");
  1204.     } else {
  1205.         printf("   program vers proto   port\n");
  1206.         for (; head != NULL; head = head->pml_next) {
  1207.             printf("%10ld%5ld",
  1208.                 head->pml_map.pm_prog,
  1209.                 head->pml_map.pm_vers);
  1210.             if (head->pml_map.pm_prot == IPPROTO_UDP)
  1211.                 printf("%6s",  "udp");
  1212.             else if (head->pml_map.pm_prot == IPPROTO_TCP)
  1213.                 printf("%6s", "tcp");
  1214.             else
  1215.                 printf("%6ld",  head->pml_map.pm_prot);
  1216.             printf("%7ld",  head->pml_map.pm_port);
  1217.             rpc = getrpcbynumber(head->pml_map.pm_prog);
  1218.             if (rpc)
  1219.                 printf("  %s\n", rpc->r_name);
  1220.             else
  1221.                 printf("\n");
  1222.         }
  1223.     }
  1224. }
  1225.  
  1226. /* 
  1227.  * reply_proc collects replies from the broadcast. 
  1228.  * to get a unique list of responses the output of rpcinfo should
  1229.  * be piped through sort(1) and then uniq(1).
  1230.  */
  1231.  
  1232. /*ARGSUSED*/
  1233. static bool_t
  1234. reply_proc(res, who)
  1235.     void *res;        /* Nothing comes back */
  1236.     struct sockaddr_in *who; /* Who sent us the reply */
  1237. {
  1238.     register struct hostent *hp;
  1239.  
  1240.     hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
  1241.         AF_INET);
  1242.     printf("%s %s\n", inet_ntoa(who->sin_addr),
  1243.         (hp == NULL) ? "(unknown)" : hp->h_name);
  1244.     return(FALSE);
  1245. }
  1246.  
  1247. static void
  1248. brdcst(argc, argv)
  1249.     int argc;
  1250.     char **argv;
  1251. {
  1252.     enum clnt_stat rpc_stat;
  1253.     u_long prognum, vers;
  1254.  
  1255.     if (argc != 2) {
  1256.         usage();
  1257.         exit(1);
  1258.     }
  1259.     prognum = getprognum(argv[0]);
  1260.     vers = getvers(argv[1]);
  1261.     rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
  1262.         (char *)NULL, xdr_void, (char *)NULL, reply_proc);
  1263.     if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
  1264.         fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
  1265.             clnt_sperrno(rpc_stat));
  1266.         exit(1);
  1267.     }
  1268.     exit(0);
  1269. }
  1270.  
  1271. static void
  1272. usage()
  1273. {
  1274.     fprintf(stderr, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n");
  1275.     fprintf(stderr, "       rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n");
  1276.     fprintf(stderr, "       rpcinfo -p [ host ]\n");
  1277.     fprintf(stderr, "       rpcinfo -b prognum versnum\n");
  1278. }
  1279.  
  1280. static u_long
  1281. getprognum(arg)
  1282.     char *arg;
  1283. {
  1284.     register struct rpcent *rpc;
  1285.     register u_long prognum;
  1286.  
  1287.     if (isalpha(*arg)) {
  1288.         rpc = getrpcbyname(arg);
  1289.         if (rpc == NULL) {
  1290.             fprintf(stderr, "rpcinfo: %s is unknown service\n",
  1291.                 arg);
  1292.             exit(1);
  1293.         }
  1294.         prognum = rpc->r_number;
  1295.     } else {
  1296.         prognum = (u_long) atoi(arg);
  1297.     }
  1298.  
  1299.     return (prognum);
  1300. }
  1301.  
  1302. static u_long
  1303. getvers(arg)
  1304.     char *arg;
  1305. {
  1306.     register u_long vers;
  1307.  
  1308.     vers = (int) atoi(arg);
  1309.     return (vers);
  1310. }
  1311.  
  1312. static void
  1313. get_inet_address(addr, host)
  1314.     struct sockaddr_in *addr;
  1315.     char *host;
  1316. {
  1317.     register struct hostent *hp;
  1318.  
  1319.     bzero((char *)addr, sizeof *addr);
  1320.     addr->sin_addr.s_addr = (u_long) inet_addr(host);
  1321.     if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
  1322.         if ((hp = gethostbyname(host)) == NULL) {
  1323.             fprintf(stderr, "rpcinfo: %s is unknown host\n", host);
  1324.             exit(1);
  1325.         }
  1326.         bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
  1327.     }
  1328.     addr->sin_family = AF_INET;
  1329. }
  1330. Funky_Stuff
  1331. len=`wc -c < rpcinfo.c`
  1332. if [ $len !=    15727 ] ; then
  1333.   echo error: rpcinfo.c was $len bytes long, should have been    15727
  1334. fi
  1335. cd ..
  1336. echo done with directory etc
  1337. echo x - demo
  1338. echo creating directory demo
  1339. mkdir demo
  1340. cd demo
  1341. echo x - Makefile
  1342. cat > Makefile <<'Funky_Stuff'
  1343. #
  1344. # @(#)Makefile    1.4 87/11/30 3.9 RPCSRC
  1345. #
  1346. #
  1347. #   Build all demo services
  1348. #
  1349. MAKE = make
  1350. LIB=-lrpclib
  1351.  
  1352. SUBDIR= dir msg sort
  1353.  
  1354. all:    ${SUBDIR}
  1355.  
  1356. clean cleanup:
  1357.     cd dir; $(MAKE) ${MFLAGS} cleanup
  1358.     cd msg; $(MAKE) ${MFLAGS} cleanup
  1359.     cd sort; $(MAKE) ${MFLAGS} cleanup
  1360.  
  1361. install:
  1362.     @echo "No installations done."
  1363.  
  1364. ${SUBDIR}:    FRC
  1365.     cd $@; $(MAKE) ${MFLAGS} LIB=$(LIB)
  1366.  
  1367. FRC:
  1368. Funky_Stuff
  1369. len=`wc -c < Makefile`
  1370. if [ $len !=      361 ] ; then
  1371.   echo error: Makefile was $len bytes long, should have been      361
  1372. fi
  1373. echo x - dir
  1374. echo creating directory dir
  1375. mkdir dir
  1376. cd dir
  1377. echo x - Makefile
  1378. cat > Makefile <<'Funky_Stuff'
  1379. #
  1380. # @(#)Makefile    1.3 87/11/30 3.9 RPCSRC
  1381. #
  1382. BIN = dir_svc rls
  1383. GEN = dir_clnt.c dir_svc.c dir_xdr.c dir.h
  1384. LIB = -lrpclib
  1385. RPCCOM = rpcgen
  1386.  
  1387. all: $(BIN)
  1388.  
  1389. $(GEN): dir.x
  1390.     $(RPCCOM) dir.x
  1391.  
  1392. dir_svc: dir_proc.o dir_svc.o dir_xdr.o
  1393.     $(CC) -o $@ dir_proc.o dir_svc.o dir_xdr.o $(LIB)
  1394.  
  1395. rls: rls.o dir_clnt.o dir_xdr.o
  1396.     $(CC) -o $@ rls.o dir_clnt.o dir_xdr.o $(LIB)
  1397.  
  1398. rls.o: rls.c dir.h
  1399.  
  1400. dir_proc.o: dir_proc.c dir.h
  1401.  
  1402. clean cleanup:
  1403.     rm -f $(GEN) *.o $(BIN)
  1404.  
  1405. Funky_Stuff
  1406. len=`wc -c < Makefile`
  1407. if [ $len !=      444 ] ; then
  1408.   echo error: Makefile was $len bytes long, should have been      444
  1409. fi
  1410. echo x - dir.x
  1411. cat > dir.x <<'Funky_Stuff'
  1412. /* @(#)dir.x    1.1 87/11/04 3.9 RPCSRC */
  1413. /*
  1414.  * dir.x: Remote directory listing protocol
  1415.  */
  1416. const MAXNAMELEN = 255;        /* maximum length of a directory entry */
  1417.  
  1418. typedef string nametype<MAXNAMELEN>;    /* a directory entry */
  1419.  
  1420. typedef struct namenode *namelist;    /* a link in the listing */
  1421.  
  1422. /*
  1423.  * A node in the directory listing
  1424.  */
  1425. struct namenode {
  1426.     nametype name;        /* name of directory entry */
  1427.     namelist next;        /* next entry */
  1428. };
  1429.  
  1430. /*
  1431.  * The result of a READDIR operation.
  1432.  */
  1433. union readdir_res switch (int errno) {
  1434. case 0:
  1435.     namelist list;    /* no error: return directory listing */
  1436. default:
  1437.     void;        /* error occurred: nothing else to return */
  1438. };
  1439.  
  1440. /*
  1441.  * The directory program definition
  1442.  */
  1443. program DIRPROG {
  1444.     version DIRVERS {
  1445.         readdir_res
  1446.         READDIR(nametype) = 1;
  1447.     } = 1;
  1448. } = 76;
  1449. Funky_Stuff
  1450. len=`wc -c < dir.x`
  1451. if [ $len !=      780 ] ; then
  1452.   echo error: dir.x was $len bytes long, should have been      780
  1453. fi
  1454. echo x - dir_proc.c
  1455. cat > dir_proc.c <<'Funky_Stuff'
  1456. /* @(#)dir_proc.c    1.3 87/11/16 3.9 RPCSRC */
  1457. /*
  1458.  * dir_proc.c: remote readdir implementation
  1459.  */
  1460. #include <rpc/rpc.h>
  1461. #include <sys/dir.h>
  1462. #include "dir.h"
  1463.  
  1464. extern int errno;
  1465. extern char *malloc();
  1466. extern char *strcpy();
  1467.  
  1468. readdir_res *
  1469. readdir_1(dirname)
  1470.     nametype *dirname;
  1471. {
  1472.     DIR *dirp;
  1473.     struct direct *d;
  1474.     namelist nl;
  1475.     namelist *nlp;
  1476.     static readdir_res res; /* must be static! */
  1477.     
  1478.     /*
  1479.      * Open directory
  1480.      */
  1481.     dirp = opendir(*dirname);
  1482.     if (dirp == NULL) {
  1483.         res.errno = errno;
  1484.         return (&res);
  1485.     }
  1486.  
  1487.     /*
  1488.      * Free previous result
  1489.      */
  1490.     xdr_free(xdr_readdir_res, &res);
  1491.  
  1492.     /*
  1493.      * Collect directory entries
  1494.      */
  1495.     nlp = &res.readdir_res_u.list;
  1496.     while (d = readdir(dirp)) {
  1497.         nl = *nlp = (namenode *) malloc(sizeof(namenode));
  1498.         nl->name = malloc(strlen(d->d_name)+1);
  1499.         strcpy(nl->name, d->d_name);
  1500.         nlp = &nl->next;
  1501.     }
  1502.     *nlp = NULL;
  1503.  
  1504.     /*
  1505.      * Return the result
  1506.      */
  1507.     res.errno = 0;
  1508.     closedir(dirp);
  1509.     return (&res);
  1510. }
  1511. Funky_Stuff
  1512. len=`wc -c < dir_proc.c`
  1513. if [ $len !=      919 ] ; then
  1514.   echo error: dir_proc.c was $len bytes long, should have been      919
  1515. fi
  1516. echo x - rls.c
  1517. cat > rls.c <<'Funky_Stuff'
  1518. /* @(#)rls.c    1.1 87/11/04 3.9 RPCSRC */
  1519. /*
  1520.  * rls.c: Remote directory listing client
  1521.  */
  1522. #include <stdio.h>
  1523. #include <rpc/rpc.h>        /* always need this */
  1524. #include "dir.h"        /* need this too: will be generated by rpcgen*/
  1525.  
  1526. extern int errno;
  1527.  
  1528. main(argc, argv)
  1529.     int argc;
  1530.     char *argv[];
  1531. {
  1532.     CLIENT *cl;
  1533.     char *server;
  1534.     char *dir;
  1535.     readdir_res *result;
  1536.     namelist nl;
  1537.     
  1538.  
  1539.     if (argc != 3) {
  1540.         fprintf(stderr, "usage: %s host directory\n", argv[0]);
  1541.         exit(1);
  1542.     }
  1543.  
  1544.     /*
  1545.      * Remember what our command line arguments refer to
  1546.      */
  1547.     server = argv[1];
  1548.     dir = argv[2];
  1549.  
  1550.     /*
  1551.      * Create client "handle" used for calling MESSAGEPROG on the
  1552.      * server designated on the command line. We tell the rpc package
  1553.      * to use the "tcp" protocol when contacting the server.
  1554.      */
  1555.     cl = clnt_create(server, DIRPROG, DIRVERS, "tcp");
  1556.     if (cl == NULL) {
  1557.         /*
  1558.          * Couldn't establish connection with server.
  1559.          * Print error message and die.
  1560.          */
  1561.         clnt_pcreateerror(server);
  1562.         exit(1);
  1563.     }
  1564.     
  1565.     /*
  1566.      * Call the remote procedure "readdir" on the server
  1567.      */
  1568.     result = readdir_1(&dir, cl);
  1569.     if (result == NULL) {
  1570.         /*
  1571.          * An error occurred while calling the server. 
  1572.           * Print error message and die.
  1573.          */
  1574.         clnt_perror(cl, server);
  1575.         exit(1);
  1576.     }
  1577.  
  1578.     /*
  1579.      * Okay, we successfully called the remote procedure.
  1580.      */
  1581.     if (result->errno != 0) {
  1582.         /*
  1583.          * A remote system error occurred.
  1584.          * Print error message and die.
  1585.          */
  1586.         errno = result->errno;
  1587.         perror(dir);
  1588.         exit(1);
  1589.     }
  1590.  
  1591.     /*
  1592.      * Successfuly got a directory listing.
  1593.      * Print it out.
  1594.      */
  1595.     for (nl = result->readdir_res_u.list; nl != NULL; nl = nl->next) {
  1596.         printf("%s\n", nl->name);
  1597.     }
  1598. }
  1599. Funky_Stuff
  1600. len=`wc -c < rls.c`
  1601. if [ $len !=     1611 ] ; then
  1602.   echo error: rls.c was $len bytes long, should have been     1611
  1603. fi
  1604. cd ..
  1605. echo done with directory dir
  1606. echo x - msg
  1607. echo creating directory msg
  1608. mkdir msg
  1609. cd msg
  1610. echo x - Makefile
  1611. cat > Makefile <<'Funky_Stuff'
  1612. #
  1613. # @(#)Makefile    1.4 87/11/30 3.9 RPCSRC
  1614. #
  1615. BIN = printmsg msg_svc rprintmsg
  1616. GEN = msg_clnt.c msg_svc.c msg.h
  1617. LIB = -lrpclib
  1618. RPCCOM = rpcgen
  1619.  
  1620. all: $(BIN)
  1621.  
  1622. #
  1623. # This is the non-networked version of the program
  1624. #
  1625. printmsg: printmsg.o
  1626.     $(CC) -o $@ printmsg.o
  1627.  
  1628. #
  1629. # note: no xdr routines are generated here, due this service's
  1630. #       use of basic data types.
  1631. #
  1632. $(GEN): msg.x
  1633.     $(RPCCOM) msg.x
  1634.  
  1635. msg_svc: msg_proc.o msg_svc.o
  1636.     $(CC) -o $@ msg_proc.o msg_svc.o $(LIB)
  1637.  
  1638. rprintmsg: rprintmsg.o msg_clnt.o
  1639.     $(CC) -o $@ rprintmsg.o msg_clnt.o $(LIB)
  1640.  
  1641. rprintmsg.o: rprintmsg.c msg.h
  1642.  
  1643. msg_proc.o: msg_proc.c msg.h
  1644.  
  1645. clean cleanup:
  1646.     rm -f $(GEN) *.o $(BIN)
  1647.  
  1648. Funky_Stuff
  1649. len=`wc -c < Makefile`
  1650. if [ $len !=      640 ] ; then
  1651.   echo error: Makefile was $len bytes long, should have been      640
  1652. fi
  1653. echo x - msg.x
  1654. cat > msg.x <<'Funky_Stuff'
  1655. /* @(#)msg.x    1.1 87/11/04 3.9 RPCSRC */
  1656. /*
  1657.  * msg.x: Remote message printing protocol
  1658.  */
  1659. program MESSAGEPROG {
  1660.     version MESSAGEVERS {
  1661.         int PRINTMESSAGE(string) = 1;
  1662.     } = 1;
  1663. } = 99;
  1664. Funky_Stuff
  1665. len=`wc -c < msg.x`
  1666. if [ $len !=      183 ] ; then
  1667.   echo error: msg.x was $len bytes long, should have been      183
  1668. fi
  1669. echo x - msg_proc.c
  1670. cat > msg_proc.c <<'Funky_Stuff'
  1671. /* @(#)msg_proc.c    1.1 87/11/04 3.9 RPCSRC */
  1672. /*
  1673.  * msg_proc.c: implementation of the remote procedure "printmessage"
  1674.  */
  1675. #include <stdio.h>
  1676. #include <rpc/rpc.h>    /* always need this here */
  1677. #include "msg.h"    /* need this too: msg.h will be generated by rpcgen */
  1678.  
  1679. /*
  1680.  * Remote verson of "printmessage"
  1681.  */
  1682. int *        
  1683. printmessage_1(msg)
  1684.     char **msg;    
  1685. {
  1686.     static int result; /* must be static! */
  1687.     FILE *f;
  1688.  
  1689.     f = fopen("/dev/console", "w");
  1690.     if (f == NULL) {
  1691.         result = 0;
  1692.         return (&result);
  1693.     }
  1694.     fprintf(f, "%s\n", *msg);
  1695.     fclose(f);
  1696.     result = 1;
  1697.     return (&result);
  1698. }
  1699. Funky_Stuff
  1700. len=`wc -c < msg_proc.c`
  1701. if [ $len !=      562 ] ; then
  1702.   echo error: msg_proc.c was $len bytes long, should have been      562
  1703. fi
  1704. echo x - printmsg.c
  1705. cat > printmsg.c <<'Funky_Stuff'
  1706. /* @(#)printmsg.c    1.1 87/11/04 3.9 RPCSRC */
  1707. /*
  1708.  * printmsg.c: print a message on the console
  1709.  */
  1710. #include <stdio.h>
  1711.  
  1712. main(argc, argv)
  1713.     int argc;
  1714.     char *argv[];
  1715. {
  1716.     char *message;
  1717.  
  1718.     if (argc < 2) {
  1719.         fprintf(stderr, "usage: %s <message>\n", argv[0]);
  1720.         exit(1);
  1721.     }
  1722.     message = argv[1];
  1723.  
  1724.     if (!printmessage(message)) {
  1725.         fprintf(stderr, "%s: sorry, couldn't print your message\n",
  1726.             argv[0]);
  1727.         exit(1);
  1728.     } 
  1729.     printf("Message delivered!\n");
  1730. }
  1731.  
  1732. /*
  1733.  * Print a message to the console.
  1734.  * Return a boolean indicating whether the message was actually printed.
  1735.  */
  1736. printmessage(msg)
  1737.     char *msg;
  1738. {
  1739.     FILE *f;
  1740.  
  1741.     f = fopen("/dev/console", "w");
  1742.     if (f == NULL) {
  1743.         return (0);
  1744.     }
  1745.     fprintf(f, "%s\n", msg);
  1746.     fclose(f);
  1747.     return(1);
  1748. }
  1749. Funky_Stuff
  1750. len=`wc -c < printmsg.c`
  1751. if [ $len !=      720 ] ; then
  1752.   echo error: printmsg.c was $len bytes long, should have been      720
  1753. fi
  1754. echo x - rprintmsg.c
  1755. cat > rprintmsg.c <<'Funky_Stuff'
  1756. /* @(#)rprintmsg.c    1.1 87/11/04 3.9 RPCSRC */
  1757. /*
  1758.  * rprintmsg.c: remote version of "printmsg.c"
  1759.  */
  1760. #include <stdio.h>
  1761. #include <rpc/rpc.h>        /* always need this */
  1762. #include "msg.h"        /* need this too: will be generated by rpcgen*/
  1763.  
  1764. main(argc, argv)
  1765.     int argc;
  1766.     char *argv[];
  1767. {
  1768.     CLIENT *cl;
  1769.     int *result;
  1770.     char *server;
  1771.     char *message;
  1772.  
  1773.     if (argc < 3) {
  1774.         fprintf(stderr, "usage: %s host message\n", argv[0]);
  1775.         exit(1);
  1776.     }
  1777.  
  1778.     /*
  1779.      * Remember what our command line arguments refer to
  1780.      */
  1781.     server = argv[1];
  1782.     message = argv[2];
  1783.  
  1784.     /*
  1785.      * Create client "handle" used for calling MESSAGEPROG on the
  1786.      * server designated on the command line. We tell the rpc package
  1787.      * to use the "tcp" protocol when contacting the server.
  1788.      */
  1789.     cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp");
  1790.     if (cl == NULL) {
  1791.         /*
  1792.          * Couldn't establish connection with server.
  1793.          * Print error message and die.
  1794.          */
  1795.         clnt_pcreateerror(server);
  1796.         exit(1);
  1797.     }
  1798.     
  1799.     /*
  1800.      * Call the remote procedure "printmessage" on the server
  1801.      */
  1802.     result = printmessage_1(&message, cl);
  1803.     if (result == NULL) {
  1804.         /*
  1805.          * An error occurred while calling the server. 
  1806.           * Print error message and die.
  1807.          */
  1808.         clnt_perror(cl, server);
  1809.         exit(1);
  1810.     }
  1811.  
  1812.     /*
  1813.      * Okay, we successfully called the remote procedure.
  1814.      */
  1815.     if (*result == 0) {
  1816.         /*
  1817.          * Server was unable to print our message. 
  1818.          * Print error message and die.
  1819.          */
  1820.         fprintf(stderr, "%s: sorry, %s couldn't print your message\n", 
  1821.             argv[0], server);    
  1822.         exit(1);
  1823.     } 
  1824.  
  1825.     /*
  1826.      * The message got printed on the server's console
  1827.      */
  1828.     printf("Message delivered to %s!\n", server);
  1829. }
  1830. Funky_Stuff
  1831. len=`wc -c < rprintmsg.c`
  1832. if [ $len !=     1599 ] ; then
  1833.   echo error: rprintmsg.c was $len bytes long, should have been     1599
  1834. fi
  1835. cd ..
  1836. echo done with directory msg
  1837. echo x - sort
  1838. echo creating directory sort
  1839. mkdir sort
  1840. cd sort
  1841. echo x - Makefile
  1842. cat > Makefile <<'Funky_Stuff'
  1843. #
  1844. # @(#)Makefile    1.4 87/11/30 3.9 RPCSRC
  1845. #
  1846.  
  1847. BIN =  rsort sort_svc
  1848. GEN = sort_clnt.c sort_svc.c sort_xdr.c sort.h
  1849. LIB = -lrpclib
  1850. RPCCOM = rpcgen
  1851.  
  1852. all: $(BIN)
  1853.  
  1854. rsort: rsort.o sort_clnt.o sort_xdr.o
  1855.     $(CC) $(LDFLAGS) -o $@ rsort.o sort_clnt.o sort_xdr.o $(LIB)
  1856.  
  1857. rsort.o: rsort.c sort.h
  1858.  
  1859. sort_clnt.c:
  1860.     $(RPCCOM) -l sort.x >$@
  1861.  
  1862. sort_svc: sort_proc.o sort_svc.o sort_xdr.o
  1863.     $(CC) $(LDFLAGS) -o $@ sort_proc.o sort_svc.o sort_xdr.o $(LIB)
  1864.  
  1865. sort_proc.o: sort_proc.c sort.h
  1866.  
  1867. sort_svc.c:
  1868.     $(RPCCOM) -s udp sort.x >$@
  1869.  
  1870. sort_xdr.c:
  1871.     $(RPCCOM) -c sort.x >$@
  1872.  
  1873. sort.h:
  1874.     $(RPCCOM) -h sort.x >$@
  1875.  
  1876. clean cleanup:
  1877.     rm -f $(GEN) *.o $(BIN)
  1878.  
  1879. Funky_Stuff
  1880. len=`wc -c < Makefile`
  1881. if [ $len !=      621 ] ; then
  1882.   echo error: Makefile was $len bytes long, should have been      621
  1883. fi
  1884. echo x - rsort.c
  1885. cat > rsort.c <<'Funky_Stuff'
  1886. /* @(#)rsort.c    1.2 87/11/24 3.9 RPCSRC */
  1887. /*
  1888.  * rsort.c
  1889.  * Client side application which sorts argc, argv.
  1890.  */
  1891. #include <stdio.h>
  1892. #include <rpc/rpc.h>
  1893. #include "sort.h"
  1894.  
  1895. main(argc, argv)
  1896.     int argc;
  1897.     char **argv;
  1898. {
  1899.     char *machinename;
  1900.     struct sortstrings args, res;
  1901.     int i;
  1902.  
  1903.     if (argc < 3) {
  1904.         fprintf(stderr, "usage: %s machinename [s1 ...]\n", argv[0]);
  1905.         exit(1);
  1906.     }
  1907.     machinename = argv[1];
  1908.     args.ss.ss_len = argc - 2;     /* substract off progname, machinename */
  1909.     args.ss.ss_val = &argv[2];
  1910.     res.ss.ss_val = (char **)NULL;
  1911.  
  1912.     if ((i = callrpc(machinename, SORTPROG, SORTVERS, SORT,
  1913.         xdr_sortstrings, &args, xdr_sortstrings, &res)))
  1914.     {
  1915.         fprintf(stderr, "%s: call to sort service failed. ", argv[0]);
  1916.         clnt_perrno(i);
  1917.         fprintf(stderr, "\n");
  1918.         exit(1);
  1919.     }
  1920.  
  1921.     for (i = 0; i < res.ss.ss_len; i++) {
  1922.         printf("%s\n", res.ss.ss_val[i]);
  1923.     }
  1924.  
  1925.     /* should free res here */
  1926.     exit(0);
  1927. }
  1928.  
  1929. Funky_Stuff
  1930. len=`wc -c < rsort.c`
  1931. if [ $len !=      897 ] ; then
  1932.   echo error: rsort.c was $len bytes long, should have been      897
  1933. fi
  1934. echo x - sort.x
  1935. cat > sort.x <<'Funky_Stuff'
  1936. /* @(#)sort.x    1.1 87/11/04 3.9 RPCSRC */
  1937. /*
  1938.  * The sort procedure receives an array of strings and returns an array
  1939.  * of strings.  This toy service handles a maximum of 64 strings.
  1940.  */
  1941. const MAXSORTSIZE  = 64;
  1942. const MAXSTRINGLEN = 64;
  1943.  
  1944. typedef    string  str<MAXSTRINGLEN>;  /* the string itself */
  1945.  
  1946. struct sortstrings {
  1947.     str ss<MAXSORTSIZE>;
  1948. };
  1949.  
  1950. program SORTPROG {
  1951.     version SORTVERS {
  1952.         sortstrings SORT(sortstrings) = 1;
  1953.     } = 1;
  1954. } = 22855;
  1955. Funky_Stuff
  1956. len=`wc -c < sort.x`
  1957. if [ $len !=      455 ] ; then
  1958.   echo error: sort.x was $len bytes long, should have been      455
  1959. fi
  1960. echo x - sort_proc.c
  1961. cat > sort_proc.c <<'Funky_Stuff'
  1962. /* @(#)sort_proc.c    1.2 87/11/24 3.9 RPCSRC */
  1963. #include <rpc/rpc.h>
  1964. #include "sort.h"
  1965.  
  1966. static int
  1967. comparestrings(sp1, sp2)
  1968.     char **sp1, **sp2;
  1969. {
  1970.     return (strcmp(*sp1, *sp2));
  1971. }
  1972.  
  1973. struct sortstrings *
  1974. sort_1(ssp)
  1975.     struct sortstrings *ssp;
  1976. {
  1977.     static struct sortstrings ss_res;
  1978.  
  1979.     if (ss_res.ss.ss_val != (str *)NULL)
  1980.         free(ss_res.ss.ss_val);
  1981.  
  1982.     qsort(ssp->ss.ss_val, ssp->ss.ss_len, sizeof (char *), comparestrings);
  1983.     ss_res.ss.ss_len = ssp->ss.ss_len;
  1984.     ss_res.ss.ss_val = (str *)malloc(ssp->ss.ss_len * sizeof(str *));
  1985.     bcopy(ssp->ss.ss_val, ss_res.ss.ss_val,
  1986.         ssp->ss.ss_len * sizeof(str *));
  1987.     return(&ss_res);
  1988. }
  1989. Funky_Stuff
  1990. len=`wc -c < sort_proc.c`
  1991. if [ $len !=      653 ] ; then
  1992.   echo error: sort_proc.c was $len bytes long, should have been      653
  1993. fi
  1994. cd ..
  1995. echo done with directory sort
  1996. cd ..
  1997. echo done with directory demo
  1998. exit
  1999.